﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace Blockey.GameObjects3D
{
    public class Grid3D
    {
        public Grid3D()
        {
            CreateLines();
        }

        public void Draw(GraphicsDevice oGraphics, Camera3D oCamera)
        {
            if (DebugShapeRenderer.ShowLines == false)
                return;

            if (m_oBasicEffect == null)
            {
                m_oBasicEffect = new BasicEffect(oGraphics);
                m_oBasicEffect.VertexColorEnabled = true;
            }

            if (oGraphics.DepthStencilState != DepthStencilState.Default)
            {
                oGraphics.DepthStencilState = DepthStencilState.Default;
            }

            oCamera.ApplyCameraEffect(ref m_oBasicEffect);

            DrawLines(oGraphics, m_oGridLines);
            DrawLines(oGraphics, m_oAxisLinesX);
            DrawLines(oGraphics, m_oAxisLinesY);
            DrawLines(oGraphics, m_oAxisLinesZ);
        }

        private void DrawLines(GraphicsDevice oGraphics, VertexPositionColor[] oLines)
        {
            // Draws Grid Lines
            foreach (EffectPass oPass in m_oBasicEffect.CurrentTechnique.Passes)
            {
                oPass.Apply();

                m_oVertexBuffer = new VertexBuffer(
                    oGraphics,
                    VertexPositionColor.VertexDeclaration,
                    oLines.Length,
                    BufferUsage.WriteOnly
                    );

                m_oVertexBuffer.SetData(0, oLines, 0, oLines.Length, 0);
                oGraphics.SetVertexBuffer(m_oVertexBuffer);

                oGraphics.DrawPrimitives(PrimitiveType.LineList, 0, oLines.Length / 2);
            }
        }

        private void CreateLines()
        {
            float fHalfLength = g_fGridSize * 0.5f;
            int fLines = (int)(fHalfLength / g_fGridSpacing);

            List<VertexPositionColor> oLines = new List<VertexPositionColor>();
            Vector3 oPointA;
            Vector3 oPointB;
            float fShiftZ = 0.1f;

            // Grid Lines
            for (int i = 1; i < fLines; i++)
            {
                oPointA = new Vector3(i * g_fGridSpacing, fHalfLength, fShiftZ);
                oPointB = new Vector3(i * g_fGridSpacing, -fHalfLength, fShiftZ);
                oLines.Add(new VertexPositionColor(oPointA, g_oGridColor));
                oLines.Add(new VertexPositionColor(oPointB, g_oGridColor));

                oPointA = new Vector3(-i * g_fGridSpacing, fHalfLength, fShiftZ);
                oPointB = new Vector3(-i * g_fGridSpacing, -fHalfLength, fShiftZ);
                oLines.Add(new VertexPositionColor(oPointA, g_oGridColor));
                oLines.Add(new VertexPositionColor(oPointB, g_oGridColor));
            }
            for (int i = 1; i < fLines; i++)
            {
                oPointA = new Vector3(fHalfLength, i * g_fGridSpacing, fShiftZ);
                oPointB = new Vector3(-fHalfLength, i * g_fGridSpacing, fShiftZ);
                oLines.Add(new VertexPositionColor(oPointA, g_oGridColor));
                oLines.Add(new VertexPositionColor(oPointB, g_oGridColor));

                oPointA = new Vector3(fHalfLength, -i * g_fGridSpacing, fShiftZ);
                oPointB = new Vector3(-fHalfLength, -i * g_fGridSpacing, fShiftZ);
                oLines.Add(new VertexPositionColor(oPointA, g_oGridColor));
                oLines.Add(new VertexPositionColor(oPointB, g_oGridColor));
            }
            m_oGridLines = oLines.ToArray();

            // X Axis
            oLines.Clear();
            oLines.Add(new VertexPositionColor(new Vector3(-fHalfLength, 0, fShiftZ), g_oAxisColorNegative));
            oLines.Add(new VertexPositionColor(new Vector3(0, 0, fShiftZ), g_oAxisColorNegative));
            oLines.Add(new VertexPositionColor(new Vector3(0, 0, fShiftZ), g_oAxisColorX));
            oLines.Add(new VertexPositionColor(new Vector3(fHalfLength, 0, fShiftZ), g_oAxisColorX));
            m_oAxisLinesX = oLines.ToArray();

            // Y Axis
            oLines.Clear();
            oLines.Add(new VertexPositionColor(new Vector3(0, -fHalfLength, fShiftZ), g_oAxisColorNegative));
            oLines.Add(new VertexPositionColor(new Vector3(0, 0, fShiftZ), g_oAxisColorNegative));
            oLines.Add(new VertexPositionColor(new Vector3(0, 0, fShiftZ), g_oAxisColorY));
            oLines.Add(new VertexPositionColor(new Vector3(0, fHalfLength, fShiftZ), g_oAxisColorY));
            m_oAxisLinesY = oLines.ToArray();

            // Z Axis
            oLines.Clear();
            oLines.Add(new VertexPositionColor(new Vector3(0, 0, -fHalfLength), g_oAxisColorNegative));
            oLines.Add(new VertexPositionColor(Vector3.Zero, g_oAxisColorNegative));
            oLines.Add(new VertexPositionColor(Vector3.Zero, g_oAxisColorZ));
            oLines.Add(new VertexPositionColor(new Vector3(0, 0, fHalfLength), g_oAxisColorZ));
            m_oAxisLinesZ = oLines.ToArray();

            oLines.Clear();
        }


        private VertexPositionColor[] m_oGridLines;
        private VertexPositionColor[] m_oAxisLinesX;
        private VertexPositionColor[] m_oAxisLinesY;
        private VertexPositionColor[] m_oAxisLinesZ;

        private VertexBuffer m_oVertexBuffer;
        private BasicEffect m_oBasicEffect;

        private const float g_fGridSpacing = 10;
        private const float g_fGridSize = 100;

        private readonly Color g_oAxisColorX = Color.Red;
        private readonly Color g_oAxisColorY = Color.Green;
        private readonly Color g_oAxisColorZ = Color.Blue;
        private readonly Color g_oAxisColorNegative = Color.White;
        private readonly Color g_oGridColor = Color.SkyBlue;

    }

}
